package com.nineclock.attendance.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.attendance.dto.AttendGroupDTO;
import com.nineclock.attendance.dto.AttendGroupPCExtraConfigDTO;
import com.nineclock.attendance.dto.AttendGroupPartDTO;
import com.nineclock.attendance.mapper.AttendGroupMapper;
import com.nineclock.attendance.mapper.AttendGroupPartMapper;
import com.nineclock.attendance.pojo.AttendGroup;
import com.nineclock.attendance.pojo.AttendGroupPart;
import com.nineclock.attendance.service.AttendGroupService;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.system.feign.SysOrganizationFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 黑马程序员
 * @Company http://www.ithiema.com
 * @Version 1.0
 */

@Service
@Slf4j
@Transactional
public class AttendGroupServiceImpl implements AttendGroupService {

    @Autowired
    AttendGroupMapper attendGroupMapper;

    @Autowired
    AttendGroupPartMapper attendGroupPartMapper;

    @Autowired
    SysOrganizationFeign organizationFeign;

    /**
     * 1. 判断是否初次使用，如果是初次，则初始化默认考勤组
     * 2. 默认考勤组关联 部门 ,关系维护
     * 3. 考勤组的分页查询
     * 4. 统计考勤组关联的员工的数量
     * 5. 组装数据并返回
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageResult<AttendGroupDTO> queryAttendGroupPage(Integer page, Integer pageSize) {
        //判断是否初次使用 , 根据企业id 查询考勤组
        LambdaQueryWrapper<AttendGroup> attendGroupQw = new LambdaQueryWrapper<>();
        attendGroupQw.eq(AttendGroup::getCompanyId, CurrentUserHolder.get().getCompanyId());
        Integer count = attendGroupMapper.selectCount(attendGroupQw);
        //如果count == 0 ，说明初次使用， 则初始化默认考勤组
        if(count == 0 ){
            //初始化默认考勤组
            AttendGroup attendGroup = this.buildDefaultAttendGroup();
            attendGroupMapper.insert(attendGroup);

            //维护 考勤组和部门员工之间的关系
            //获取所有一级部门
            List<Long> departmentIds = organizationFeign.queryDepartmentIds().getData();
            if(CollectionUtil.isNotEmpty(departmentIds)){
                for (Long departmentId : departmentIds) {
                    AttendGroupPart attendGroupPart = new AttendGroupPart();
                    attendGroupPart.setAttendGroupId(attendGroup.getId()); //考勤组id
                    attendGroupPart.setObjectType(1); //对象类型
                    attendGroupPart.setObjectId(departmentId); // 对象（部门/用户）的id
                    attendGroupPart.setAttendType(1); //是否参加考勤

                    attendGroupPartMapper.insert(attendGroupPart);
                }

            }
        }

        //分页查询
        Page<AttendGroup> attendGroupPage = new Page<>(page, pageSize);
        attendGroupQw = new LambdaQueryWrapper<>();
        attendGroupQw.eq(AttendGroup::getCompanyId, CurrentUserHolder.get().getCompanyId());
        //分页查询， 获取分页结果对象
        attendGroupPage = attendGroupMapper.selectPage( attendGroupPage , attendGroupQw);
        //当前页要展示的数据
        List<AttendGroup> records = attendGroupPage.getRecords();
        if(CollectionUtil.isNotEmpty(records)){
            //如果 records 不为null， 则转换为 DTO对象
            List<AttendGroupDTO> attendGroupDTOS = BeanHelper.copyWithCollection(records, AttendGroupDTO.class);

            for (AttendGroupDTO attendGroupDTO : attendGroupDTOS) {
                //查询 考勤组 与部门和员工的关系
                LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
                attendGroupPartQw.eq(AttendGroupPart::getAttendGroupId, attendGroupDTO.getId());
                //获取该考勤组的关系列表
                List<AttendGroupPart> attendGroupPartList = attendGroupPartMapper.selectList(attendGroupPartQw);
                //统计 关系表中的 部门类型的数据
                //filter : 返回值为boolean ， 如果是true，则包含数据，false，则不包含数据
                List<Long> departmentIds = attendGroupPartList.stream().filter(attendGroupPart -> {
                    if (attendGroupPart.getObjectType() == 1) {
                        return true;
                    }
                    return false;
                }).map(attendGroupPart -> {
                    return attendGroupPart.getObjectId();
                }).collect(Collectors.toList());
                //统计 关系表中的员工的 id
                List<Long> userIds = attendGroupPartList.stream().filter(attendGroupPart -> {
                    return attendGroupPart.getObjectType() == 2;
                }).map(attendGroupPart -> {
                    return attendGroupPart.getObjectId();
                }).collect(Collectors.toList());

                Integer departmentUserCount = 0;
                //查询部门对应的员工数量
                if(CollectionUtil.isNotEmpty(departmentIds)){
                    departmentUserCount = organizationFeign.queryUserCountByDepartmentIds(departmentIds).getData();
                }


                //设置的员工的数量：  userIds.size() +  部门下的员工数量
                attendGroupDTO.setMemberNum((userIds == null ? 0:userIds.size()) + departmentUserCount);
            }


            return new PageResult(attendGroupPage.getTotal(), attendGroupPage.getPages(), attendGroupDTOS);
        }

        return new PageResult();
    }

    @Override
    public void addAttendGroup(AttendGroupDTO attendGroupDTO) {
        if(attendGroupDTO == null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //BeanHelper.copyProperties 只能复制 相同类型，相同属性名 的字段
        //把attendGroupDTO转换为 pojo 对象
        AttendGroup attendGroup = BeanHelper.copyProperties(attendGroupDTO, AttendGroup.class);

        //工作日 设置
        List<String> workdays = attendGroupDTO.getWorkdays();
        String workdaysStr = StrUtil.join(",", workdays.toArray());
        attendGroup.setWorkdays(workdaysStr);

        //设置基本信息
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setCreateTime(new Date());
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());

        //需要打卡的日期列表
        List<String> necessaryTime = new ArrayList<>();
        //无需打卡的日期列表
        List<String> unNecessaryTime = new ArrayList<>();
        //设置需要打卡  和无需打卡 的日期
        List<AttendGroupPCExtraConfigDTO> extraConfig = attendGroupDTO.getExtraConfig();
        for (AttendGroupPCExtraConfigDTO attendGroupPCExtraConfigDTO : extraConfig) {
            if(attendGroupPCExtraConfigDTO.getRequiredAttend() == 1){
                necessaryTime.add(attendGroupPCExtraConfigDTO.getSetDate());
            } else{
                unNecessaryTime.add(attendGroupPCExtraConfigDTO.getSetDate());
            }
        }
        //设置需要打卡的 日期列表
        attendGroup.setNecessaryTimeList(StrUtil.join(",", necessaryTime));
        //设置无需打卡的日期列表
        attendGroup.setUnnecessaryTimeList(StrUtil.join(",", unNecessaryTime));

        //新增 考勤组对象
        attendGroupMapper.insert(attendGroup);

        //维护 考勤组 和部门，员工之间的关系
        //获取  需要考勤 信息
        List<AttendGroupPartDTO> participates = attendGroupDTO.getParticipates();

        if(CollectionUtil.isNotEmpty(participates)){
            for (AttendGroupPartDTO participate : participates) {

                //先删除 部门或者员工 与 其他考勤组的关系
                LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
                //设置 类型 （部门、员工）
                attendGroupPartQw.eq(AttendGroupPart::getObjectType, participate.getObjectType());
                //设置 部门、员工 的 id
                attendGroupPartQw.eq(AttendGroupPart::getObjectId, participate.getObjectId());
                // 删除原来的关系
                attendGroupPartMapper.delete(attendGroupPartQw);

                // 在维护新的关系
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId());
                attendGroupPart.setObjectType(participate.getObjectType());
                attendGroupPart.setObjectId(participate.getObjectId());
                attendGroupPart.setAttendType(1);

                attendGroupPartMapper.insert(attendGroupPart);

            }

        }


        //获取 无需考勤的信息
        List<AttendGroupPartDTO> notParticipates = attendGroupDTO.getNotParticipates();

        if(CollectionUtil.isNotEmpty(notParticipates)){
            for (AttendGroupPartDTO participate : notParticipates) {

                //先删除 部门或者员工 与 其他考勤组的关系
                LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
                //设置 类型 （部门、员工）
                attendGroupPartQw.eq(AttendGroupPart::getObjectType, participate.getObjectType());
                //设置 部门、员工 的 id
                attendGroupPartQw.eq(AttendGroupPart::getObjectId, participate.getObjectId());
                // 删除原来的关系
                attendGroupPartMapper.delete(attendGroupPartQw);

                // 在维护新的关系
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId());
                attendGroupPart.setObjectType(participate.getObjectType());
                attendGroupPart.setObjectId(participate.getObjectId());
                attendGroupPart.setAttendType(2);

                attendGroupPartMapper.insert(attendGroupPart);

            }

        }
    }


    @Override
    public AttendGroupDTO getAttendGroupByUserId() {
        //获取 当前登录的用户id
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();
        //从 关系表中 获取 该员工与考勤组的关系
        LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
        attendGroupPartQw.eq(AttendGroupPart::getObjectType, 2 );
        attendGroupPartQw.eq(AttendGroupPart::getObjectId, companyUserId);

        AttendGroupPart attendGroupPart = attendGroupPartMapper.selectOne(attendGroupPartQw);
        if(attendGroupPart == null){
            //如果没有查询到关系， 根据部门查询关系
            //获取 该员工所在的部门id集合
            List<Long> ids = organizationFeign.queryDepartmentsByUserId(companyUserId).getData();

            if(CollectionUtil.isNotEmpty(ids)){
                for (Long id : ids) {
                    attendGroupPartQw = new LambdaQueryWrapper<>();
                    attendGroupPartQw.eq(AttendGroupPart::getObjectType, 1);
                    attendGroupPartQw.eq(AttendGroupPart::getObjectId, id);
                    attendGroupPart = attendGroupPartMapper.selectOne(attendGroupPartQw);
                    if(attendGroupPart != null){
                        break;
                    }
                }
            }

        }

        if (attendGroupPart != null){
            Long attendGroupId = attendGroupPart.getAttendGroupId();
            //获取考勤组 对象
            AttendGroup attendGroup = attendGroupMapper.selectById(attendGroupId);
            if(attendGroup != null){
                AttendGroupDTO attendGroupDTO = BeanHelper.copyProperties(attendGroup, AttendGroupDTO.class);
                //设置工作日信息
                String workdays = attendGroup.getWorkdays();
                //把字符串切割转换为 list集合
                List<String> list = Arrays.asList(workdays.split(","));
                attendGroupDTO.setWorkdays(list);


                return attendGroupDTO;
            }

        }

        return null;
    }

    private AttendGroup buildDefaultAttendGroup() {
        AttendGroup attendGroup = new AttendGroup();
        attendGroup.setName("默认考勤组");
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());
        attendGroup.setStartWorkTime("09:00:00");
        attendGroup.setAllowLateMinutes(10);
        attendGroup.setLateMinutes(30);
        attendGroup.setStartNoonRestTime("12:00:00");
        attendGroup.setEndNoonRestTime("14:00:00");
        attendGroup.setOffWorkTime("18:00:00");
        attendGroup.setWorkdays("1,1,1,1,1,0,0");
        attendGroup.setAddress("金燕龙办公楼");
        attendGroup.setAddressName("金燕龙总部");
        attendGroup.setLat(new BigDecimal(116.343368));
        attendGroup.setLng(new BigDecimal(40.060456));
        attendGroup.setAddressRange(1000);
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setCreateTime(new Date());

        return attendGroup;
    }
}
